<template>
  <base-container>
    <!-- 搜索栏 -->
    <avue-table-search
      :option="searchOption"
      v-model="searchParams"
      @search-change="loadTableSearch"
      @search-reset="loadTableSearchReset"
    />

    <base-table-card>
      <template #header-right>
        <el-button type="primary" v-auth="[PERMS.SERVICE.CATEGORY.ADD]" @click="onAddRoot"> 新增服务类目</el-button>
      </template>

      <avue-crud
        ref="crudRef"
        :option="tableOption"
        :data="tableData"
        v-model="formData"
        :page="page"
        :table-loading="tableLoading"
        @refresh-change="loadGetTableData"
        @current-change="loadTablePageChange"
        @size-change="loadTablePageSizeChange"
        @row-save="loadAdd"
        @row-update="loadEdit"
      >
        <!-- 上级类目（表单显示值） -->
        <template #parentName-form>
          <span>{{ formData?.parentName || "主类目" }}</span>
        </template>

        <!-- 展示状态开关：用 @change，避免刷新时误触发 -->
        <template #displayStatus="{ row }">
          <el-switch
            :model-value="row.displayStatus"
            :loading="row._statusLoading"
            :active-value="1"
            :inactive-value="0"
            :disabled="!canToggleDisplay"
            :before-change="() => handleToggleDisplay(row)"
          />
        </template>

        <!-- 操作列 -->
        <template #menu="{ row }">
          <!-- 编辑 -->
          <el-button type="primary" text v-auth="[PERMS.SERVICE.CATEGORY.UPDATE]" @click="onEdit(row)">编辑</el-button>

          <!-- 只有一级/二级才能"加下级"（第三级不显示） -->
          <el-button
            v-if="canAddChild(row)"
            type="primary"
            v-auth="[PERMS.SERVICE.CATEGORY.ADD]"
            text
            @click="onAddChild(row)"
          >
            加下级
          </el-button>

          <!-- 删除：不可删时禁用 + 提示，可删时可点 -->
          <template v-if="!canDelete(row)">
            <el-tooltip :content="deleteTip(row)" placement="top">
              <el-button v-auth="[PERMS.SERVICE.CATEGORY.DELETE]" text disabled>删除</el-button>
            </el-tooltip>
          </template>
          <el-button v-else v-auth="[PERMS.SERVICE.CATEGORY.DELETE]" type="danger" text @click="loadDel(row)">
            删除
          </el-button>
        </template>
      </avue-crud>
    </base-table-card>
  </base-container>
</template>

<script setup>
  import Option from "@/crudOption/service/category";
  import { ElMessageBox } from "element-plus";
  import { useUserInfoStore } from "@/store/modules/userInfo.js";
  import { PERMS } from "@/constants/perms.js";

  const user = useUserInfoStore();
  const canToggleDisplay = computed(() => user.hasAuth([PERMS.SERVICE.CATEGORY.ENABLE]));
  /* ================== CRUD Hook ================== */
  let {
    data: tableData,
    loading: tableLoading,
    page,
    search: searchParams,
    form: formData,
    get: loadGetTableData,
    add: loadAdd,
    edit: loadEdit,
    del: loadDel,
    pageNumChange: loadTablePageChange,
    pageSizeChange: loadTablePageSizeChange,
    searchReset: loadTableSearchReset,
    searchChange: loadTableSearch,
  } = useCrudHook({
    get: Api.service.GetServiceCategoryList,
    add: Api.service.AddServiceCategory,
    edit: Api.service.UpdateServiceCategory,
    del: Api.service.DelServiceCategory,
    dataRes: "data", // 返回 data 为数组
    // 搜索参数格式化
    getParamsFormat: p => {
      const params = { ...p };
      if (Array.isArray(params.createTime) && params.createTime.length === 2) {
        params.createTimeStart = params.createTime[0];
        params.createTimeEnd = params.createTime[1];
      }
      if (Array.isArray(params.updateTime) && params.updateTime.length === 2) {
        params.updateTimeStart = params.updateTime[0];
        params.updateTimeEnd = params.updateTime[1];
      }
      if (params.displayStatus === "") delete params.displayStatus; // 空值不传
      delete params.createTime;
      delete params.updateTime;
      return params;
    },

    // 新增参数格式化
    addParamsFormat: row => ({
      ...row,
      applicableObjects: Array.isArray(row.applicableObjects)
        ? row.applicableObjects.join(",")
        : row.applicableObjects || "",
      displayStatus: Number(row.displayStatus ?? 1),
      sortNo: Number(row.sortNo ?? 1),
      platform: 1,
    }),

    // 编辑参数格式化
    editParamsFormat: row => ({
      ...row,
      applicableObjects: Array.isArray(row.applicableObjects)
        ? row.applicableObjects.join(",")
        : row.applicableObjects || "",
      displayStatus: Number(row.displayStatus ?? 1),
      sortNo: Number(row.sortNo ?? 1),
    }),
  });

  // 配置
  const { searchOption, tableOption } = Option();
  /* ===== 适用对象：全量字典 & 按父级裁剪 ===== */

  // 拿到表单里“适用对象”字段的配置
  const getApplicableCol = () => tableOption.value?.group?.[0]?.column?.applicableObjects;

  // 强制使用本地 dicData（如果配置里写了 dicUrl，这里删掉它）
  function ensureLocalApplicableDic() {
    const col = getApplicableCol();
    if (!col) return;
    delete col.dicUrl;
    delete col.dicQuery;
    col.dicData ||= [];
  }

  // 缓存全量字典
  const ALL_APPLICABLE = ref([]);

  // 拉取字典并写入到配置（根级默认显示全部）
  async function loadApplicableDict() {
    const res = await Api.dict.GetListChildrenByDictCode({
      dictCode: "qingyun.support.serviceCenter.applicableObject",
    });
    ALL_APPLICABLE.value = (res?.data || [])
      .map(i => ({ label: i.dictLabel, value: String(i.dictValue) }))
      .filter(o => o.value !== "01"); // ★ 这里剔除 '01'

    const col = getApplicableCol();
    if (col) col.dicData = ALL_APPLICABLE.value.slice();
  }

  // 工具：把 "01,02" → ["01","02"]
  const parseCodes = v =>
    String(v ?? "")
      .split(",")
      .map(s => s.trim())
      .filter(Boolean);

  // 工具：把“适用对象”字段可选项裁剪为 codes 子集（codes 为空 = 全部）
  function limitApplicableTo(codes) {
    const col = getApplicableCol();
    if (!col) return;
    const set = new Set((codes || []).map(String));
    col.dicData =
      set.size === 0 ? ALL_APPLICABLE.value.slice() : ALL_APPLICABLE.value.filter(o => set.has(String(o.value)));
  }

  // 工具：找父节点（编辑时需要）
  function findNodeById(list, id) {
    if (!id) return null;
    for (const n of list || []) {
      if (n.id === id) return n;
      const hit = findNodeById(n.children, id);
      if (hit) return hit;
    }
    return null;
  }
  /* ================== 基础引用 ================== */
  const crudRef = ref(null);
  tableOption.value.menu = computed(() =>
    user.hasAuth([
      "ope.support.serviceCategory.update",
      "ope.support.serviceCategory.add",
      "ope.support.serviceCategory.delete",
    ])
  );
  /* ================== 新增/编辑 ================== */
  // 新增根级
  // 根级新增：显示全部选项
  function onAddRoot() {
    formData.value.parentId = 0;
    formData.value.parentName = "主类目";
    limitApplicableTo([]); // 全部可选
    formData.value.applicableObjects = []; // 让用户自行勾选
    crudRef.value?.rowAdd();
  }

  // 在某行下新增：选项 = 父级 codes，并默认勾选父级
  function onAddChild(row) {
    formData.value.parentId = row.id;
    formData.value.parentName = row.categoryName;

    const parentCodes = parseCodes(row.applicableObjects);
    limitApplicableTo(parentCodes);
    formData.value.applicableObjects = parentCodes.slice(); // 默认勾选父级
    crudRef.value?.rowAdd();
  }

  // 编辑：同样受父级限制，且把自身越界值收敛掉
  function onEdit(row) {
    const parent = findNodeById(tableData.value, row.parentId);
    const parentCodes = parseCodes(parent?.applicableObjects);
    const ownCodes = parseCodes(row.applicableObjects);

    limitApplicableTo(parentCodes);
    const allow = new Set(parentCodes);
    const safeOwn = parentCodes.length ? ownCodes.filter(c => allow.has(c)) : ownCodes;

    const parentName = findParentName(tableData.value, row.parentId) || "主类目";
    crudRef.value?.rowEdit({
      ...row,
      parentName,
      applicableObjects: safeOwn,
    });
  }

  // 递归找父级名称
  function findParentName(list, pid) {
    if (!pid) return "";
    for (const n of list || []) {
      if (n.id === pid) return n.categoryName;
      const hit = findParentName(n.children, pid);
      if (hit) return hit;
    }
    return "";
  }

  /* ================== 层级标注（不依赖后端 _level） ================== */
  const levelMap = ref(new Map());

  function markLevels(list, level = 1) {
    if (!Array.isArray(list)) return;
    for (const node of list) {
      levelMap.value.set(node.id, level);
      node._level = level; // 方便调试/查看
      if (Array.isArray(node.children) && node.children.length) {
        markLevels(node.children, level + 1);
      }
    }
  }

  watch(
    tableData, // 直接传 ref
    val => {
      levelMap.value = new Map();
      markLevels(Array.isArray(val) ? val : [], 1);
    },
    { immediate: true }
  );

  /* ================== 操作列规则 ================== */
  const hasChildren = row => Array.isArray(row?.children) && row.children.length > 0;
  const hasContent = row => Number(row?.contentNum ?? 0) > 0;

  // 只有一级/二级可“加下级”
  const canAddChild = row => (levelMap.value.get(row.id) ?? 1) < 3 && row.displayStatus == 1;

  // 删除可用性与提示
  const canDelete = row => !hasChildren(row) && !hasContent(row);
  const deleteTip = row => {
    if (hasChildren(row)) return "该类目存在下级，请先删除其下级类目后再删除";
    if (hasContent(row)) return "该类目下已有内容，请先迁移内容后再删除";
    return "";
  };

  /* ================== 展示状态开关（确认 + loading） ================== */
  // 是否有子级（优先用行内数据，兜底请求后端计数；按你们实际接口名替换）
  async function hasChildrenAsync(row) {
    if (Array.isArray(row.children)) return row.children.length > 0;
    if (typeof row.childCount === "number") return row.childCount > 0;
    try {
      const r = await Api.service.GetCategoryChildrenCount?.({ id: row.id });
      const n = r?.data?.count ?? r?.count ?? 0;
      return n > 0;
    } catch {
      return false;
    }
  }
  async function handleToggleDisplay(row) {
    const closing = row.displayStatus === 1; // 当前是开启 → 将要关闭
    const nextVal = closing ? 0 : 1;

    // 关闭时，若有子级，提示“关闭后其下的子级也将同步关闭……”
    let tip = closing ? "确定要关闭该类目吗？关闭后不在前端展示。" : "确定要开启该类目吗？";
    if (closing && (await hasChildrenAsync(row))) {
      tip = "关闭后其下的子级也将同步关闭，确定关闭吗？";
    }

    try {
      await ElMessageBox.confirm(tip, "提示", { type: "warning" });
    } catch {
      return false; // 用户取消
    }

    row._statusLoading = true;
    try {
      await Api.service.StatusCategoryEnableChange({
        id: row.id,
        displayStatus: nextVal,
      });

      $msg.success(nextVal ? "已开启" : "已关闭");
      await loadGetTableData();
      return true; // ✅ 通知 el-switch 切换成功
    } catch (e) {
      console.error("[onToggleCategory]", e);
      return false; // 切换失败，保持原状
    } finally {
      row._statusLoading = false;
    }
  }

  /* ================== 挂载 ================== */
  onMounted(async () => {
    ensureLocalApplicableDic(); // 强制走 dicData
    await loadApplicableDict(); // 先把全量字典写进配置
    loadGetTableData(); // 再拉树数据
  });
</script>

<style lang="scss" scoped></style>
